package com.qd.pandaparkflow.compment.park;

import cn.hutool.core.date.LocalDateTimeUtil;
import com.qd.common.panda.domain.entity.rule.*;
import com.qd.common.panda.domain.enums.CarParkBillRuleEnum;
import com.qd.pandaparkflow.context.PriceContext;
import com.qd.pandaparkflow.dto.PerViewDTO;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.core.NodeComponent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;

/**
 * 分时段
 * 分时段按小时[]
 */
@ConditionalOnProperty(prefix = "liteflow", name = "enable", havingValue = "true")
@LiteflowComponent(value = "periodCmp")
@Slf4j
public class PeriodComponent extends NodeComponent {
    private static final String TIME_START_MSG = ",开始时间[";
    private static final String TIME_END_MSG = ",结束时间[";
    private static final String CONDITION_MINUTES = "满足条件的分钟数[";
    @Resource
    private FlowExecutor flowExecutor;

    @Override
    public void process() throws Exception {

        final PriceContext priceContext = this.getContextBean(PriceContext.class);
        final List<BaseRuleDTO> rules = priceContext.getRules();
        Collections.copy(priceContext.getRules(), rules);
        switch (Objects.requireNonNull(CarParkBillRuleEnum.getByValue(priceContext.getBillRule()))) {
            case BILL_RULE4:
                //分时段按小时
                for (BaseRuleDTO rule : rules) {
                    if (rule instanceof Rule4DTO) {
                        rule4((Rule4DTO) rule);
                    }
                }
                break;
            case BILL_RULE5:
                //分时段有起步价按小时
                for (BaseRuleDTO rule : rules) {
                    if (rule instanceof Rule5DTO) {
                        rule5((Rule5DTO) rule);
                    }
                }
                break;
            case BILL_RULE6:
                //混合
                for (BaseRuleDTO rule : rules) {
                    if (rule instanceof Rule6DTO) {
                        rule6((Rule6DTO) rule);
                    }
                }
                break;
            default:
                break;
        }
    }


    /**
     * 分时段按小时，如“白天（8点至24点），每小时5元，夜间（24点至8点），每小时3元
     * [{
     * "start": "00:00:00",
     * "end": "08:00:00",
     * "price": 5
     * }, {
     * "start": "08:00:00",
     * "end": "23:59:59",
     * "price": 33
     * }]
     */
    public void rule4(Rule4DTO rule) {
        StringBuilder logBuilder = new StringBuilder();
        final PriceContext priceContext = this.getContextBean(PriceContext.class);
        final long minutes = getMinutes(rule.getStart(), rule.getEnd(), priceContext.getStartTime(), priceContext.getEndTime());
        logBuilder.append("分时段按小时计费,时段:[").append(rule.getStart().toString()).append("-").append(rule.getEnd().toString()).append("]")
                .append(TIME_START_MSG).append(priceContext.getStartTime().toString()).append("]").append(TIME_END_MSG).append(priceContext.getEndTime()).append("]")
                .append(CONDITION_MINUTES).append(minutes).append("]");
        priceContext.setMinutes(minutes);
        priceContext.setUnitPrice(rule.getPrice());
        priceContext.getPrintLog().add(logBuilder.toString());
        flowExecutor.invoke2Resp("baseBillRule1", "", this.getSlotIndex());
    }

    /**
     * 分时段有起价按小时计费，如“白天（8点至24点），前两小时5元，以后每小时3元，夜间（24点至8点），前两小时3元，以后每小时1元。不足半小时按半小时计费，超过半小时按1小时计费
     * [{
     * "start": "00:00:00",
     * "end": "08:00:00",
     * "startHour": 2,
     * "startPrice": 3,
     * "price": 2
     * }, {
     * "start": "08:00:00",
     * "end": "23:59:59",
     * "startHour": 2,
     * "startPrice": 5,
     * "price": 3
     * }]
     */
    public void rule5(Rule5DTO rule){
        StringBuilder logBuilder = new StringBuilder();
        final PriceContext priceContext = this.getContextBean(PriceContext.class);
        final long minutes = getMinutes(rule.getStart(), rule.getEnd(), priceContext.getStartTime(), priceContext.getEndTime());
        logBuilder.append("分时段有起价按小时计费,时段:[").append(rule.getStart().toString()).append("-").append(rule.getEnd().toString()).append("]")
                .append(TIME_START_MSG).append(priceContext.getStartTime().toString()).append("]").append(TIME_END_MSG).append(priceContext.getEndTime()).append("]")
                .append(CONDITION_MINUTES).append(minutes).append("]");
        priceContext.setMinutes(minutes);
        rule2(rule.getStartPrice(), rule.getStartHour(), rule.getPrice(), priceContext);
        priceContext.getPrintLog().add(logBuilder.toString());
    }

    /**
     * 6、分时段混合计费，如“白天（8点至24点），前两小时5元，以后每小时3元，夜间（24点至8点），每次5元”
     * [{
     * "start": "00:00:00",
     * "end": "08:00:00",
     * "everyTimePrice": 5
     * }, {
     * "start": "08:00:00",
     * "end": "23:59:59",
     * "startHour": 2,
     * "startPrice": 5,
     * "price": 3
     * }]
     */
    public void rule6(Rule6DTO rule) {
        StringBuilder logBuilder = new StringBuilder();
        final PriceContext priceContext = this.getContextBean(PriceContext.class);
        final long minutes = getMinutes(rule.getStart(), rule.getEnd(), priceContext.getStartTime(), priceContext.getEndTime());
        priceContext.setMinutes(minutes);
        logBuilder.append("分时段混合计费,时段:[").append(rule.getStart().toString()).append("-").append(rule.getEnd().toString()).append("]")
                .append(TIME_START_MSG).append(priceContext.getStartTime().toString()).append("]").append(TIME_END_MSG).append(priceContext.getEndTime()).append("]")
                .append(CONDITION_MINUTES).append(minutes).append("]");
        if (Optional.ofNullable(rule.getEveryTimePrice()).orElse(new BigDecimal(0L)).signum() == BigInteger.ONE.signum()) {
            PerViewDTO perViewDTO = new PerViewDTO();
            perViewDTO.setStartTime(rule.getStart())
                    .setEndTime(rule.getEnd())
                    .setUnitPrice(rule.getEveryTimePrice());
            priceContext.setPerView(perViewDTO);
            flowExecutor.invoke2Resp("perViewCmpChain", "", this.getSlotIndex());
        } else {

            rule2(rule.getStartPrice(), rule.getStartHour(), rule.getPrice(), priceContext);
        }
        priceContext.getPrintLog().add(logBuilder.toString());

    }

    private void rule2(BigDecimal startPrice, Integer startHour, BigDecimal price, PriceContext priceContext) {
        Rule2DTO rule2DTO = new Rule2DTO();
        rule2DTO.setStartPrice(startPrice)
                .setStartHour(startHour)
                .setPrice(price);
        priceContext.setUnitPrice(price);
        ArrayList<BaseRuleDTO> arrayList = new ArrayList<>();
        arrayList.add(rule2DTO);
        priceContext.setRules(arrayList);
        flowExecutor.invoke2Resp("baseBillRule2", "", this.getSlotIndex());
    }

    /**
     * 计算总时间
     *
     * @param startTime 计费开始时段
     * @param endTime   计费结束时段
     * @param start     停车开始时间
     * @param end       停车结束时间
     * @return 满足条件时间和
     */
    public long getMinutes(LocalTime startTime, LocalTime endTime, LocalDateTime start, LocalDateTime end) {
        long minutes = 0;
        final Duration duration = LocalDateTimeUtil.between(start, end);
        long days = duration.toDays();
        if (duration.toHours() > 0) {
            days += 1;
        }
        //相差的天数
        for (int i = 0; i < days; i++) {
            LocalDateTime s = start;
            LocalDateTime e = end;
            LocalDate localDate = start.toLocalDate();
            if (i == 0) {
                //第一天的结束时间
                e = LocalDateTime.of(localDate.getYear(), localDate.getMonth(), localDate.getDayOfMonth(), 23, 59, 59);
            }
            if (i > 0) {
                localDate = localDate.plusDays(1);
                s = LocalDateTime.of(localDate.getYear(), localDate.getMonth(), localDate.getDayOfMonth(), 0, 0, 0);
            }
            if (s.isBefore(start)) {
                s = start;
            }
            if (e.isAfter(end)) {
                e = end;
            }
            //拼装当天的开始时间和结束时间
            LocalDateTime startLocalDateTime = LocalDateTime.of(localDate.getYear(), localDate.getMonth(), localDate.getDayOfMonth(), startTime.getHour(), startTime.getMinute(), startTime.getSecond());
            LocalDateTime endLocalDateTime = LocalDateTime.of(localDate.getYear(), localDate.getMonth(), localDate.getDayOfMonth(), endTime.getHour(), endTime.getMinute(), endTime.getSecond());
            endLocalDateTime = endLocalDateTime.isAfter(e) ? e : endLocalDateTime;

            if (LocalDateTimeUtil.isOverlap(startLocalDateTime, endLocalDateTime, s, e)) {
                minutes += LocalDateTimeUtil.between(startLocalDateTime, endLocalDateTime).toMinutes();
                log.info("s:{},e:{},startLocalDateTime:{},endLocalDateTime:{},minutes:{}", LocalDateTimeUtil.formatNormal(s), LocalDateTimeUtil.formatNormal(e), LocalDateTimeUtil.formatNormal(startLocalDateTime), LocalDateTimeUtil.formatNormal(endLocalDateTime), minutes);
            }
        }
        return minutes;
    }
}